/*
 * BlackLightning.PluginLib.Modules.Packets.StormFront.SFSpeechCommandPacket
 * Andy Tidball
 * 
 * Project: Black Lightning Plugin Library
 * Copyright: GNU General Public License
 */

using System;
using System.Collections.Generic;
using System.Text;
using BlackLightning.PluginLib.Modules.Packets;

namespace BlackLightning.PluginLib.Modules.Packets.StormFront {
    /// <summary>
    /// The StormFront implementation of SpeechCommandPacket.
    /// </summary>
    [Serializable]
    public class SFSpeechCommandPacket : SpeechCommandPacket {
        /// <summary>
        /// Parses an SFSpeechCommandPacket from a string of data.
        /// </summary>
        /// <param name="Source">The program that the data came from.</param>
        /// <param name="Data">The data to parse.</param>
        /// <returns>An SFSpeechCommandPacket created from the given data, or null if the data cannot be parsed.</returns>
        public static SFSpeechCommandPacket Parse(Program Source, string Data) {
            // trim the whitespace
            string Remainder = Data.Trim();

            // make sure the data is long enough
            if (Remainder.Length < 4) {
                return null;
            }

            // make sure there's a command tag
            if (!Remainder.StartsWith("<c>")) {
                return null;
            }

            // remove the command tag
            Remainder = Remainder.Substring(3);

            // make sure there's a valid speech verb
            if (Remainder.Length >= 4 && Remainder.Substring(0,4).ToLower() == "say ") {
                Remainder = Remainder.Substring(4);
            } else if (Remainder.Length >= 1 && Remainder.StartsWith("'")) {
                Remainder = Remainder.Substring(1);
            } else if (Remainder.Length >= 2 && Remainder.StartsWith("\"")) {
                Remainder = Remainder.Substring(1);
            } else {
                return null;
            }

            // look for the rest of the Remainder
            string   Target   = null;
            string   Tone     = null;
            string   Style    = null;
            string   Language = null;
            string   Throw    = null;
            string[] Split    = Remainder.Split(' ');
            int      Index    = 0;
            for (Index=0; Index<Split.Length; ++Index) {
                string Arg = Split[Index];
                if (Target == null && Arg.Length > 2 && Arg.StartsWith("::")) {
                    Target = Arg.Substring(2);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Target == null && Arg.Length > 1 && Arg.StartsWith("@")) {
                    Target = Arg.Substring(1);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Target == null && Arg.Length > 2 && Arg.StartsWith("{") && Arg.EndsWith("}")) {
                    Target = Arg.Substring(1, Arg.Length-2);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Tone == null && Arg.Length > 1 && Arg.StartsWith(":")) {
                    Tone = Arg.Substring(1);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Style == null && Arg.Length > 1 && Arg.StartsWith("=")) {
                    Style = Arg.Substring(1);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Language == null && Arg.Length > 1 && Arg.StartsWith("~")) {
                    Language = Arg.Substring(1);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Throw == null && Arg.Length > 1 && Arg.StartsWith("]")) {
                    Throw = Arg.Substring(1);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else if (Throw == null && Arg.Length > 2 && Arg.StartsWith("[") && Arg.EndsWith("]")) {
                    Throw = Arg.Substring(1, Arg.Length-2);
                    Remainder = Remainder.Substring(Arg.Length + 1);
                } else {
                    break;
                }
            }

            // make sure there's some text left
            if (Remainder.Length > 0) {
                return null;
            }

            // create and return the packet
            return new SFSpeechCommandPacket(Source, Program.GameServer, Data, Remainder, Target, Tone, Style, Language, Throw);
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text)
            : this(Source, Destination, null, Text, null, null, null, null, null) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text, string Target)
            : this(Source, Destination, null, Text, Target, null, null, null, null) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        /// <param name="Tone">The tone of the speech.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text, string Target, string Tone)
            : this(Source, Destination, null, Text, Target, Tone, null, null, null) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        /// <param name="Tone">The tone of the speech.</param>
        /// <param name="Style">The style of the speech.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text, string Target, string Tone, string Style)
            : this(Source, Destination, null, Text, Target, Tone, Style, null, null) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        /// <param name="Tone">The tone of the speech.</param>
        /// <param name="Style">The style of the speech.</param>
        /// <param name="Language">The language being spoken.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text, string Target, string Tone, string Style, string Language)
            : this(Source, Destination, null, Text, Target, Tone, Style, Language, null) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        /// <param name="Tone">The tone of the speech.</param>
        /// <param name="Style">The style of the speech.</param>
        /// <param name="Language">The language being spoken.</param>
        /// <param name="Throw">The object the speech is being "thrown" behind.</param>
        public SFSpeechCommandPacket(Program Source, Program Destination, string Text, string Target, string Tone, string Style, string Language, string Throw)
            : this(Source, Destination, null, Text, Target, Tone, Style, Language, Throw) {
        }

        /// <summary>
        /// Creates a new SFSpeechCommandPacket.
        /// </summary>
        /// <param name="Source">The program that the packet came from.</param>
        /// <param name="Destination">The program that the packet will be delivered to.</param>
        /// <param name="Data">The data string the packet was parsed from.</param>
        /// <param name="Text">The text being spoken.</param>
        /// <param name="Target">The name of the person being spoken to.</param>
        /// <param name="Tone">The tone of the speech.</param>
        /// <param name="Style">The style of the speech.</param>
        /// <param name="Language">The language being spoken.</param>
        /// <param name="Throw">The object the speech is being "thrown" behind.</param>
        private SFSpeechCommandPacket(Program Source, Program Destination, string Data, string Text, string Target, string Tone, string Style, string Language, string Throw)
            : base(Source, Destination, Data, Text, Target, Tone, Style, Language, Throw) {
        }

        /// <summary>
        /// Retrieves the packet's data.
        /// </summary>
        /// <returns>The packet's data string.</returns>
        public override string CreateOutput() {
            // start with a command tag and verb
            StringBuilder Output = new StringBuilder("<c>say ");

            // append any modifiers that we have
            if (this.Target != null) {
                Output.AppendFormat("@{0} ", this.Target);
            }
            if (this.Tone != null) {
                Output.AppendFormat(":{0} ", this.Tone);
            }
            if (this.Style != null) {
                Output.AppendFormat("={0} ", this.Style);
            }
            if (this.Language != null) {
                Output.AppendFormat("~{0} ", this.Language);
            }
            if (this.Throw != null) {
                Output.AppendFormat("]{0} ", this.Throw);
            }

            // append the text
            Output.Append(this.Text);

            // return the result
            return Output.ToString();
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="P">The SFSpeechCommandPacket to create a copy of.</param>
        /// <param name="DeepCopyOrNextState">True to make a deep copy of the given packet, false to instead use the given packet as the new packet's previous state.</param>
        protected SFSpeechCommandPacket(SFSpeechCommandPacket P, bool DeepCopyOrNextState)
            : base(P, DeepCopyOrNextState) {
        }

        /// <summary>
        /// Creates a deep copy of the packet.
        /// </summary>
        /// <returns>A deep copy of the packet.</returns>
        public override object Clone() {
            return new SFSpeechCommandPacket(this, true);
        }

        /// <summary>
        /// Creates a new SFCommandPacket that has this SFCommandPacket as its PreviousState.
        /// </summary>
        /// <returns>A new SFCommandPacket that has this one as its PreviousState.</returns>
        internal override BLPacket GetNextState() {
            return new SFSpeechCommandPacket(this, false);
        }
    }
}
